
package it.polito.let.jhp.parser;

import java_cup.runtime.*;
import java.io.IOException;
import it.polito.let.jhp.types.*;
import it.polito.let.jhp.form.*;

import static it.polito.let.jhp.parser.JHPSym.*;

%%

%class JHPLex

%unicode
%line
%column

%public
// %final
// %abstract

%cupsym JHPSym
//%standalone
%cup
//%cupdebug

%xstate jhp
%xstate form
%xstate jhpform
%xstate flush
 

%init{
	// TODO: code that goes to constructor
%init}

%{
	private static final boolean DEBUG = false;
	
	private Symbol sym(int type)
	{
		return new Symbol(type, yyline, yycolumn); 
	}

	private Symbol sym(int type, Object value)
	{
		return new Symbol(type, yyline, yycolumn, value);
	}

	private void error()
	throws IOException
	{
		throw new IOException("illegal text at line = "+yyline+", column = "+yycolumn+", text = '"+yytext()+"'");
	}
	
	private void trace(String s) {
		if (DEBUG)
			System.out.println(s);
	}

   public static final char DEFAULT_ESCAPE = '\\';
	
  /** 
   * Utility method to remove escape characters from the specified
   * String.
   */
 
  public static String unescape(final String s, char escape) {
    final int len = s.length();
    StringBuffer buffer = new StringBuffer(len);
    for (int i = 0; i < len; i++) {
      char ch = s.charAt(i);
      if (ch == escape) {
        i++;
        if (i == len)
          return buffer.toString();
        ch = s.charAt(i);
      }
      buffer.append(ch);
    }
    return buffer.toString();
  }
	
	private String parseString (String s) {
		String result = s.trim().substring(1,s.length()-1);
		return unescape(result,DEFAULT_ESCAPE);
	}
%}

nl 			=	\r|\n|\r\n
ws 			= 	[ \t]
INTEGER		=   ("+"|"-")?[1-9][0-9]*|0
FLOAT		=	("+"|"-")?(([0-9]+"."[0-9]*)|([0-9]*"."[0-9]+))(e|E("+"|"-")?[0-9]+)?
STRING		= 	\"([^\n\r\"]+|\\\")*\"
BOOL		=	true|false
ID 			= 	[A-Za-z_][0-9A-Za-z_]*
JAVASTMT	=	"{$" ([^$] | "$"[^}])* "$}"
TYPE		=	Integer | String | Float | Boolean | Enum
RENDER		=	select | radio | checkbox
ATTRIBUTE	=	"minLength" | "maxLength" | "pattern" | "range" | "render" | "enumerate"
ORIGINALTYPE =	"type" 
AGGREGATOR	=	"ALL" | "CHOICE"
ANY			=	.
JHPOPEN		=	"<!--@"
JHPCLOSE 	=	"@-->"
HTMLNORMAL  =	"<" ({ws}|{nl})*  ([a-zA-Z/?] | "!DOCTYPE" | "!--" [^@]) .* | [^< \t\r\n]  .*
FORMOPEN	=	"<" ({ws}|{nl})*  "form" ({ws}|{nl})* ">"
FORMCLOSE	=	"<" ({ws}|{nl})* "/" ({ws}|{nl})* "form" ({ws}|{nl})* ">" 
COMMENT		=	"//" .* | "<!--" [^@] (.| {nl})* [^@] "-->"


%%

{JHPOPEN}								{ yybegin(jhp); trace("JHPBEGIN"); /*return sym(JHPSym.JHPBEGIN);*/ }

<jhp>{JHPOPEN}							{ error(); }
<jhp>{JHPCLOSE}							{ yybegin(YYINITIAL); }
<jhp>"jhpForm"							{ yybegin(form); trace("JHPFORM"); }
<jhp>"jhpType"							{ trace("JHPTYPE"); return sym(JHPSym.JHPTYPE); }
<jhp, jhpform>"{"						{ trace("{"); return sym(JHPSym.GRAFOPEN); }
<jhp, jhpform>"}"						{ trace("}"); return sym(JHPSym.GRAFCLOSE); }

<form,jhp>"="							{ trace("EQUALS"); return sym(JHPSym.EQUALS); }

<jhp>"("								{ trace("("); return sym(JHPSym.TONDAOPEN); }
<jhp>")"								{ trace(")"); return sym(JHPSym.TONDACLOSE); }
<jhp>"["								{ trace("["); return sym(JHPSym.SQUAREOPEN); }
<jhp>"]"								{ trace("]"); return sym(JHPSym.SQUARECLOSE); }
<jhp>";"								{ trace(";"); return sym(JHPSym.SEMICOLON); }
<jhp>","								{ trace(","); return sym(JHPSym.COLON); }
<jhp>":"								{ trace(":"); return sym(JHPSym.DP); }
<jhp>"|"								{ trace("PIPE"); return sym(JHPSym.PIPE); }
<jhp>{ORIGINALTYPE}						{ trace("ORIGINALTYPE"); return sym(JHPSym.ORIGINALTYPE); }
<jhp>{TYPE}								{ trace("TYPE: "+yytext()); try { return sym(JHPSym.TYPE,new String(yytext())); } catch (Exception e) { error(); } }
<jhp>{RENDER}							{ trace("RENDER: "+yytext()); try { return sym(JHPSym.RENDER, RenderType.valueOf(yytext())); } catch (Exception e) { error(); } }
<jhp>{ATTRIBUTE}						{ trace("ATTRIBUTE: "+yytext()); try { return sym(JHPSym.ATTRIBUTE, TypeAttr.valueOf(yytext())); } catch (Exception e) { error(); } }
<jhp>{BOOL}								{ trace("BOOLEAN: "+yytext()); try { return sym(JHPSym.BOOLEAN,new Boolean(yytext())); } catch (Exception e) { error(); } }
<jhp>{FLOAT}							{ trace("FLOAT: "+yytext()); try { return sym(JHPSym.FLOAT,new Float(yytext())); } catch (Exception e) { error(); } }
<jhp>{INTEGER}							{ trace("INTEGER: "+yytext()); try {return sym(JHPSym.INTEGER,new Integer(yytext()));} catch (Exception e) { error(); } }

<form>{JHPOPEN}							{ trace("JHPOPEN");  yybegin(jhpform); }
<jhpform>{JHPOPEN}						{ error(); }
<form, jhpform>{JHPCLOSE}				{ trace("JHPCLOSE");  yybegin(form); }
<jhpform>{JHPCLOSE}/[^<]				{ trace("JHPCLOSE");  yybegin(flush); }
<jhpform>{AGGREGATOR}					{ trace("AGGREGATOR: "+yytext()); try { return sym(JHPSym.AGGREGATOR,AggregatorType.valueOf(yytext())); } catch (Exception e) { error(); } }

<form>{FORMOPEN}						{ trace("FORMOPEN"); return sym(JHPSym.FORMOPEN); }
<form>{FORMCLOSE}						{ trace("FORMCLOSE"); yybegin(YYINITIAL); return sym(JHPSym.FORMCLOSE);}
<form>"<"								{ trace("TAGOPEN"); return sym(JHPSym.TAGOPEN); }
<form>">"/[^<]							{ trace("TAGCLOSE"); yybegin(flush); return sym(JHPSym.TAGCLOSE); }
<form>">"								{ trace("TAGCLOSE"); return sym(JHPSym.TAGCLOSE); }
<form>"/"								{ trace("SLASH"); return sym(JHPSym.SLASH); }
<form,jhp>{ID}							{ trace("ID: "+yytext()); try { return sym(JHPSym.ID,new String(yytext())); } catch (Exception e) { error(); } }		
<form,jhp>{STRING}						{ trace("STRING: "+yytext()); try { return sym(JHPSym.STRING,parseString(yytext())); } catch (Exception e) { error(); } }
<form,jhp>{JAVASTMT}					{ trace("JAVA STATEMENT: "+yytext()); try { return sym(JHPSym.JAVASTMT,new String(yytext())); } catch (Exception e) { error(); } }
<form>{COMMENT}/[^<]					{ trace("COMMENT: "+yytext()); yybegin(flush); }

{HTMLNORMAL}							{ trace("HTMLCODE: "+yytext()); try { return sym(JHPSym.HTMLCODE,new String(yytext())); } catch (Exception e) { error(); } }

<flush>[^<]*							{ trace("LITERAL: "+yytext()); yybegin(form); try { return sym(JHPSym.LITERAL,new String(yytext())); } catch (Exception e) { error(); } }

<YYINITIAL,jhp,form,jhpform>{ws}|{nl}	{ ; }
<jhp,form,jhpform>{COMMENT}				{ trace("COMMENT: "+yytext()); }
<jhp,form,jhpform>{ANY}					{ error(); }